from urllib import urlopen
import feedparser

# try to use faster cPickle implementation, but fall back on python
# implementation if it's not available
try:
    from cPickle import dump, load
except:
    from pickle import dump, load


shows_url = 'http://ted.svn.sourceforge.net/svnroot/ted/trunk/webservices/shows.xml'
default_conf_path = 'gats.pickle'


# -- model objects --

class Show:
   def __init__(self, name='', feeds=None):
        self.name = name
        if feeds is None:
            self.feeds = []
        else:
            self.feeds = feeds
    
class Subscription:
    def __init__(self, name='', feeds=None, fromCatalog=False):
        self.name = name
        self.fromCatalog = fromCatalog
        if not fromCatalog:
            if feeds is None:
                self.feeds = []
            else:
                self.feeds = feeds
        
    def feeds(self, shows): # get the list of feeds, even if this sub is from the catalog
        if self.fromCatalog:
            return shows[self.name].feeds
        else:
            return self.feeds

class Feed:
    def __init__(self, url):
        self.url = url
        self.data = None

    def __getitem__(self, key):             return self.data[key]
    def __setitem__(self, key, item):       self.data[key] = item

    def fetch(self):
        if self.data:
            etag = self.data.etag
            modified = self.data.modified
        else:
            etag = None
            modified = None

        d = feedparser.parse(self.url, etag=etag, modified=modified)
        
        if (d.entries != []):   # no error or 304
            self.data = d
        
        return d.status


# -- the GATS controller --

class Gats:

    def __init__(self, conf_path=default_conf_path):
        self.conf_path = conf_path
        self.load_conf()
        if not self.shows: # fixme or some time has passed
            self.download_shows()


    # -- loading and storing data --
    
    def download_shows(self):
        # get a file handle to the XML list
        try:
            showlist_handle = urlopen(shows_url)
        except:
            print "couldn't download show list"
            return
    
        import xml.sax, xml.sax.handler
        class showsHandler(xml.sax.handler.ContentHandler):
            def __init__(self):
                self.inShow = False # currently parsing a "show" element?
                self.inName = False
                self.inFeed = False
                self.shows = {}
                
            def startElement(self, name, attrs):
                if name == 'show':
                    self.curShow = Show()
                    self.inShow = True
                elif self.inShow: # only pay attention if we're parsing a show
                    if name == 'name':
                        self.text = ''
                        self.inName = True
                    if name == 'feed':
                        self.text = ''
                        self.inFeed = True
            
            def endElement(self, name):
                if name == 'show':
                    self.shows[self.curShow.name] = self.curShow
                    self.inShow = False
                elif self.inShow:
                    if name == 'name': # finished parsing a show name
                        self.curShow.name = self.text
                        self.inName = False
                    if name == 'feed': # ... or feed URL
                        self.curShow.feeds.append(Feed(self.text))
                        self.inFeed = False
                    
            def characters(self, ch):
                if self.inName or self.inFeed: # accumulate characters for text fields
                    self.text += ch
        handler = showsHandler()
        xml.sax.parse(showlist_handle, handler)
        self.shows = handler.shows # fixme only on success (otherwise, leave alone or init to {})

    def load_conf(self):
        try:
            f = open(self.conf_path)
            (self.shows, self.subs) = load(f)
            f.close()
        except:
            # assume first run
            (self.shows, self.subs) = ([], [])

    def save_conf(self):
        try:
            f = open(self.conf_path, 'wb')
            dump((self.shows, self.subs),f)
            f.close()
        except:
            print "couldn't save configuration"
